package com.yumeng.framework.auth.shiro.filter;

import com.yumeng.framework.auth.bean.VerifyLoginInfo;
import com.yumeng.framework.auth.helper.HttpTokenHelper;
import com.yumeng.framework.auth.service.TokenService;
import com.yumeng.framework.auth.shiro.token.JwtToken;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;

/**
 * jwt认证过滤器
 *
 * @author wxd
 * @date 2022/6/1 16:12
 */
@Slf4j
public class JwtFilter extends AbstractStatelessFilter {

    public static final String FILTER_NAME = "jwtFilter";

    private final TokenService tokenService;

    public JwtFilter(TokenService tokenService){
        this.tokenService = tokenService;
    }

    @Override
    public String getFilteredFlagName() {
        return "myJwtFilter.FILTERED";
    }


    @Override
    protected AuthenticationToken doCreateToken(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpRequest = WebUtils.toHttp(request);
        String jwtToken = HttpTokenHelper.getToken(httpRequest);
        if (StringUtils.isBlank(jwtToken)){
            throw new AuthenticationException("token缺失，请重新登录后再试");
        }
        String refreshToken = HttpTokenHelper.getRefreshToken(httpRequest);
        return new JwtToken(jwtToken, refreshToken, getHost(request));
    }

    /**
     * 登录前置处理
     * 验证token有效性
     * @param token
     * @param request
     * @param response
     * @return
     */
    @Override
    protected VerifyLoginInfo onPreLogin(AuthenticationToken token, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpResponse = WebUtils.toHttp(response);
        if(token instanceof JwtToken){
            VerifyLoginInfo info = tokenService.preVerifyTokenInfo(JwtToken.createTokenInfo((JwtToken)token), httpResponse);
            return info;
        }
        return null;
    }

    /**
     * 登录成功后
     * 执行
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, VerifyLoginInfo info, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpResponse = WebUtils.toHttp(response);
        if(token instanceof JwtToken){
            tokenService.refreshToken(JwtToken.createTokenInfo((JwtToken)token), info, httpResponse);
        }
        return true;
    }

    /**
     * 登录失败后
     *
     * @param token
     * @param e
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        log.error("JwtFilter::onLoginFailure token:{}, error:{}", token.toString(), e.getMessage());
        //此处要抛出异常，如果只return false，异常将无法被捕捉，前端获取不到具体的异常信息
        throw e;
    }
}
